﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Axa.CasinoApp.Client.WP7;
using CasinoApp.Models;
using CasinoApp.Views;
using Axa.CasinoApp.Client.ProcessLayer.UseCases;
using CasinoApp.ProcessLayer.WebRequest;

namespace CasinoApp.Tools
{
    /// <summary>
    /// Klasse zur Verwaltung Steuerung der SlotMachine-Stati und Slot-Werte.
    /// </summary>
    /// <param author="">Aeschlimann Thomas, 2011 AXA</param>
    public class SlotMachineController
    {
        #region Fields

        /// <summary>
        /// Speichert die Anzahl der Slots für der SlotMachine.
        /// </summary>
        private int _numberOfSlots;

        /// <summary>
        /// Speichert einen Array mit den Symbol-Nummern für die einzelnen Slots, bei welchen gestoppt werden soll.
        /// </summary>
        private int[] _symbolsToStop;

        /// <summary>
        /// Speichert den Wert ob der User gewonnen hat.
        /// </summary>
        private bool _userWins = false;

        /// <summary>
        /// Speichert den Wert ob die SlotMachine läuft.
        /// </summary>
        private bool _isRunning = false;

        /// <summary>
        /// Anzahl Sekunden für welche die SlotMachine ausgeführt werden soll.
        /// </summary>
        private int _runDurationSeconds;

        /// <summary>
        /// Speichert den Sekunden-Abstand, in welchem die einzelnen Slots gestoppt werden sollen.
        /// </summary>
        private const int STOP_INTERVAL_SECONDS = 2;

        /// <summary>
        /// NavigationService mit welchem zwischen den Views gewechselt werden kann.
        /// </summary>
        private INavigate _navigater;

        #endregion // Fields

        #region Konstruktoren

        /// <summary>
        /// Konstruktor unter Angabe der Anzahl Slots.
        /// </summary>
        /// <param name="numberOfSlots">Anzahl Slots für die SlotMachine.</param>
        public SlotMachineController(int numberOfSlots, INavigate navigater)
        {
            _numberOfSlots = numberOfSlots;
            _symbolsToStop = new int[_numberOfSlots];
            _navigater = navigater;
            SettingsModel = new SettingsModel();
        }

        #endregion // Konstruktoren

        #region Properties

        public SettingsModel SettingsModel { get; set; }

        /// <summary>
        /// Gibt den Array für die zu stoppenden Bilder-Nummern pro Slot zurück.
        /// </summary>
        public int[] SymbolsToStop
        {
            get
            {
                return _symbolsToStop;
            }
        }

        /// <summary>
        /// Gibt den Wert, ob der User gewonnen hat zurück.
        /// </summary>
        public bool UserWins
        {
            get
            {
                bool allSymbolsAreIdentical = true;
               
                for (int i = 0; i < _symbolsToStop.Length; i++)
                {
                    if (i > 0)
                    {
                        if (_symbolsToStop[i] != _symbolsToStop[i - 1])
                        {
                            allSymbolsAreIdentical = false;
                            break;
                        }
                    }
                }

                return allSymbolsAreIdentical;
            }
        }

        /// <summary>
        /// Gibt den Wert ob die SlotMachine läuft an oder ruft ihn ab.
        /// </summary>
        public bool IsRunning
        {
            get
            {
                return _isRunning;
            }
        }

        #endregion // Properties

        #region Events

        /// <summary>
        /// Event der gefeuert wird, wenn die SlotMachine gestoppt werden soll.
        /// </summary>
        public event EventHandler<EventArgs> StopSlotMachineRequested;

        /// <summary>
        /// Event der gefeuert wird, wenn ein Slot gestoppt werden soll.
        /// </summary>
        public event EventHandler<StopSlotRequestedEventArgs> StopSlotRequested;

        /// <summary>
        /// Event der gefeuert wird, wenn der Stop-Timer gestoppt wurde.
        /// </summary>
        public event EventHandler<EventArgs> SlotMachineStopped;

        #endregion // Events

        #region Methoden

        public void InitializeNewGame()
        {
            IGameUseCase gu;

            gu = CreateGameUseCase();

            gu.InitializeGameRequestCompleted += new EventHandler(InitializeGameRequestCompletedHandler);
            gu.InitializeGameAsync(SettingsModel.NumberOfPlayers);
        }

        private IGameUseCase CreateGameUseCase()
        {
            IGameUseCase gu;
            if (SettingsModel.UseBackend)
            {
                gu = new GameUseCase(SettingsModel.BackendUrl);
            }
            else
            {
                gu = new GameUseCaseMock();
            }
            return gu;
        }

        /// <summary>
        /// Started die SlotMachine für die angegebene Dauer.
        /// </summary>
        /// <param name="runDurationSeconds">Anzahl Sekunden für welche die SlotMachine ausgeführt werden soll.</param>
        public void StartSlotMachine(int runDurationSeconds)
        {
            _runDurationSeconds = runDurationSeconds;

            IGameUseCase gameUseCase = CreateGameUseCase();
            gameUseCase.GetPotRequestCompleted += new EventHandler<GetPotResponseEventArgs>(GetPotRequestCompletedHandler);
            gameUseCase.GetPotAsync();
        }

        private void GetPotRequestCompletedHandler(object sender, GetPotResponseEventArgs e)
        {
            _symbolsToStop[0] = e.PotResponse.NumberRow1;
            _symbolsToStop[1] = e.PotResponse.NumberRow2;
            _symbolsToStop[2] = e.PotResponse.NumberRow3;

            _isRunning = true;

            SlotMachineTimer slotMachineRunTimer = new SlotMachineTimer(_numberOfSlots);
            slotMachineRunTimer.RunTimerStopped += new EventHandler<EventArgs>(RunTimerStoppedHandler);
            slotMachineRunTimer.StartRunningSequence(_runDurationSeconds); 
        }

        /// <summary>
        /// Führt den Stop-Prozess für die einzlenen Slots aus.
        /// </summary>
        private void StopSlotMachine()
        {
            SlotMachineTimer slotMachineStopTimer = new SlotMachineTimer(_numberOfSlots);
            slotMachineStopTimer.StopSlotRequested += new EventHandler<StopSlotRequestedEventArgs>(StopSlotRequestedHandler);
            slotMachineStopTimer.StopTimerStopped += new EventHandler<EventArgs>(StopTimerStoppedHandler);
            slotMachineStopTimer.StartStoppingSequence(STOP_INTERVAL_SECONDS);
        }

        /// <summary>
        /// Speilt den PullArm-SoundClip ab.
        /// </summary>
        public void PlayPullArmSoundClip()
        {
            PlaySound("PullArm.wav", 0.4f);
            Thread.Sleep(300);
        }

        /// <summary>
        /// Speilt den RunningWheel-SoundClip ab.
        /// </summary>
        public void PlayRunningWheelSoundClip()
        {
            PlaySound("RunningWheel.wav", 1f);
        }

        /// <summary>
        /// Speilt den StopWheel-SoundClip ab.
        /// </summary>
        public void PlayStopWheelSoundClip()
        {
            PlaySound("StopWheel.wav", 0.7f);
        }

        /// <summary>
        /// Speilt den Loose-SoundClip ab.
        /// </summary>
        public void PlayLooseSoundClip()
        {
            PlaySound("Loose.wav", 1f);
        }

        /// <summary>
        /// Speilt den Jackpot-SoundClip ab.
        /// </summary>
        public void PlayJackpotSoundClip()
        {
            PlaySound("Jackpot.wav", 0.6f);
        }

        /// <summary>
        /// Speilt einen SoundClip von einem WAV File ab.
        /// </summary>
        private void PlaySound(string soundClipFileName, float volume)
        {
            using (var stream = TitleContainer.OpenStream(string.Format("_Sounds/SlotMachine/{0}", soundClipFileName)))
            {
                var effect = SoundEffect.FromStream(stream);
                FrameworkDispatcher.Update();
                effect.Play(volume, 0, 0);
                //Thread.Sleep(effect.Duration);
            }
        }

        #endregion // Methoden

        #region Event-Handler

        /// <summary>
        /// Wird aufgerufen sobald der Run-Timer durchgelausen ist. Feuert den StopSlotMachineRequested-Event.
        /// </summary>
        /// <param name="sender">Das auslösende Objekt.</param>
        /// <param name="eventArgs">Standard EventArgs.</param>
        private void RunTimerStoppedHandler(object sender, EventArgs eventArgs)
        {
            StopSlotMachine();

            EventHandler<EventArgs> handler = StopSlotMachineRequested;

            if (handler != null)
            {
                handler(this, eventArgs);
            }
        }

        /// <summary>
        /// Wird aufgerufen sobald ein Slot gestoppt werden soll. Feuert den StopSlotRequested-Event.
        /// </summary>
        /// <param name="sender">Das auslösende Objekt.</param>
        /// <param name="eventArgs">StopSlotMachineBarRequestedEventArgs.</param>
        private void StopSlotRequestedHandler(object sender, StopSlotRequestedEventArgs eventArgs)
        {
            PlayStopWheelSoundClip();

            EventHandler<StopSlotRequestedEventArgs> handler = StopSlotRequested;

            if (handler != null)
            {
                handler(this, eventArgs);
            }
        }

        /// <summary>
        /// Wird aufgerufen sobald der Stop-Timer für das Stoppen der Slots gestoppt wurde. Feuert den TimerStopped-Event.
        /// </summary>
        /// <param name="sender">Das auslösende Objekt.</param>
        /// <param name="eventArgs">StopSlotMachineBarRequestedEventArgs.</param>
        private void StopTimerStoppedHandler(object sender, EventArgs eventArgs)
        {
            _isRunning = false;

            if (UserWins)
            {
                PlayJackpotSoundClip();
            }
            else
            {
                PlayLooseSoundClip();
            }

            EventHandler<EventArgs> handler = SlotMachineStopped;

            if (handler != null)
            {
                handler(this, eventArgs);
            }
        }

        /// <summary>
        /// Wird ausgeführt sobald das Game auf dem Backend initialisiert wurde.
        /// </summary>
        private void InitializeGameRequestCompletedHandler(object sender, EventArgs e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                _navigater.Navigate(new Uri("/Views/SlotMachinePage.xaml", UriKind.Relative));
            });
        }

        #endregion // Event-Handler

    }
}
